home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / idioms.lha / idioms / 5-11.c < prev    next >
C/C++ Source or Header  |  1993-08-08  |  5KB  |  209 lines

  1. /* Copyright (c) 1992 by AT&T Bell Laboratories. */
  2. /* Advanced C++ Programming Styles and Idioms */
  3. /* James O. Coplien */
  4. /* Fixed by Andy Piper - Cambridge University Engineering Department */
  5. /* All rights reserved. */
  6.  
  7. #include <stddef.h>
  8. #include <memory.h>
  9.  
  10. class LAPD {
  11.     friend class LAPDMemoryManager;
  12.   public:
  13.     void *operator new(size_t);
  14.     void operator delete(void *);
  15.     LAPD(char *const);
  16.     virtual ~LAPD() {}
  17.   protected:
  18.     LAPD() { /* no-op */ }
  19.     
  20.   private:
  21.   int:8;
  22.     struct {
  23.     unsigned char flag;
  24.     unsigned int sapi:6;
  25.     unsigned int commandResponse:1;
  26.     unsigned int zero:1;
  27.     unsigned int tei:7;
  28.     unsigned int ext:1;
  29.     unsigned char control;
  30.     } header;
  31.     struct {
  32.     LAPD *linkf, *linkb;
  33.     unsigned short logSize;
  34.     } minfo;
  35.   protected:
  36.     union {
  37.     unsigned char tag;   // minfo system allocated tag
  38.     size_t    size;
  39.     };
  40.     void performCRCCheck() { /* . . . */ }
  41. };
  42.  
  43. #define round(a,b) (((a+b-1)/b)*b)
  44.  
  45. class LAPDMemoryManager {
  46.     friend LAPD;
  47.   private:
  48.     enum { MessageBufSize=8192, Log2MessageBufSize=13 };
  49.     unsigned char availBuf[
  50.     (1+Log2MessageBufSize)*round(sizeof(LAPD),4)];
  51.     LAPD *avail;
  52.     unsigned char buf[MessageBufSize];
  53.     LAPD *buddy(int k, LAPD *l) {
  54.         unsigned char *cp = (unsigned char *) l;
  55.         return (LAPD*)(buf+(long(cp-buf) ^ (1<<k)));
  56.     }
  57.   public:
  58.     LAPDMemoryManager();
  59.     int savej;
  60.     LAPD *largestBlock();
  61.     void allocateResizeBlock(int ktemp);
  62.     void deallocateBlock(LAPD *l, int k);
  63. };
  64.  
  65. LAPDMemoryManager::LAPDMemoryManager() {
  66.     LAPD* buf = (LAPD*)this->buf;
  67.     avail = (LAPD*)availBuf;
  68.     avail[Log2MessageBufSize].minfo.linkf = 
  69.     avail[Log2MessageBufSize].minfo.linkb = buf;
  70.     buf[0].minfo.linkf = buf[0].minfo.linkb =
  71.     &avail[Log2MessageBufSize];
  72.     buf[0].tag = 1;        /* unused */
  73.     buf[0].minfo.logSize = Log2MessageBufSize;
  74.     for (int k = 0; k < Log2MessageBufSize; k++) {
  75.     avail[k].minfo.linkf = avail[k].minfo.linkb =
  76.         (LAPD*)&avail[k];
  77.     
  78.     }
  79. }
  80. LAPD * LAPDMemoryManager::largestBlock() {
  81.     for (int k = Log2MessageBufSize; k >= 0; --k) {
  82.     if (avail[k].minfo.linkf != &avail[k]) {
  83.         savej = k;
  84.         return avail[k].minfo.linkf;
  85.     }
  86.     }
  87.     return 0;
  88. }
  89. void LAPDMemoryManager::allocateResizeBlock(int ktemp) {
  90.     int k, j = savej;
  91.         // Round up to next 2**n
  92.     for (int i = 1; i < Log2MessageBufSize; i++) {
  93.     k = 1 << i;
  94.     if (k > ktemp) break;
  95.     }
  96.     LAPD *l = avail[j].minfo.linkf;
  97.     avail[j].minfo.linkf = l->minfo.linkf;
  98.     l->minfo.linkf->minfo.linkb = &avail[j];
  99.     for(l->tag = 0; j - i; ) {
  100.     --j;
  101.     LAPD *p = (LAPD*)(((char *)l) + (1 << j));
  102.     p->tag = 1;
  103.     p->minfo.logSize = j;
  104.     p->minfo.linkf = p->minfo.linkb = &avail[j];
  105.     avail[j].minfo.linkf = avail[j].minfo.linkb = p;
  106.     }
  107. }
  108.  
  109. void LAPDMemoryManager::deallocateBlock(LAPD *l, int ktemp) {
  110.     int i;
  111.     for (int k = 0; k < Log2MessageBufSize; k++) {
  112.     i = 1 << k;
  113.     if (i >= ktemp) break;
  114.     }
  115.     for(;;) {
  116.     LAPD *p = buddy(k,l);
  117.     if (k==Log2MessageBufSize || p->tag == 0 || p->minfo.logSize != k) {
  118.         break;
  119.     }
  120.     p->minfo.linkb->minfo.linkf = p->minfo.linkf;
  121.     p->minfo.linkf->minfo.linkb = p->minfo.linkb;
  122.     ++k;
  123.     if (p < l) l = p;
  124.     }
  125.     l->tag = 1;
  126.     l->minfo.linkf = avail[k].minfo.linkf;
  127.     avail[k].minfo.linkb = l;
  128.     l->minfo.logSize = k;
  129.     l->minfo.linkb = &avail[k];
  130.     avail[k].minfo.linkf = l;
  131. }
  132.  
  133. static LAPDMemoryManager manager;
  134.  
  135. // this operator allows one object in the LAPD
  136. // hierarchy to overlay itself with an instance
  137. // of one of its derived classes
  138.  
  139. inline void *operator new(size_t, LAPD* l) { return l; }
  140.  
  141. class X25: public LAPD {
  142.     friend LAPD;
  143.   private:
  144.     struct X25PacketBody {
  145.     unsigned char rep[128];
  146.     };
  147.     ~X25() { if (!size) size = sizeof(X25); }
  148.     X25(char *const m): LAPD() {
  149.         manager.allocateResizeBlock( sizeof(X25) );
  150.         ::memcpy(&body, m, sizeof(body));
  151.     }
  152.     X25PacketBody body;
  153.     
  154. };
  155.  
  156. class EIN: public LAPD {
  157.     friend LAPD;
  158.   private:
  159.     struct EINPacketBody {
  160.     unsigned char rep[256];
  161.     };
  162.     ~EIN() { if (!size) size = sizeof(EIN); }
  163.     EIN(char *const m): LAPD() {
  164.         manager.allocateResizeBlock( sizeof(EIN) );
  165.         ::memcpy(&body, m, sizeof(body));
  166.     }
  167.     EINPacketBody body;
  168. };
  169.  
  170. void *
  171. LAPD::operator new(size_t /* unused */) {
  172.     return manager.largestBlock();
  173. }
  174.  
  175. void
  176. LAPD::operator delete(void *l) {
  177.     manager.deallocateBlock((LAPD*)l, ((LAPD*)l)->size);
  178. }
  179.  
  180. LAPD::LAPD(char *const bits) {
  181.     ::memcpy(&header, bits, sizeof(header));
  182.     performCRCCheck();
  183.     
  184.     // Determine type of message based on address
  185.     switch(bits[0]) {
  186.       case 'a':
  187.         (void) ::new(this) X25(bits); break;
  188.       case 'b':
  189.         (void) ::new(this) EIN(bits); break;
  190.       default:
  191.         // error("invalid message"); break;
  192.         ;
  193.     }
  194. }
  195.  
  196. int main() {
  197.     LAPD *m, *n, *o, *p;
  198.     m = new LAPD("abcdefg");
  199.     n = new LAPD("badfljk;adsflkj;asldf");
  200.     delete n;
  201.     n = new LAPD("aadflkj;sadf");
  202.     o = new LAPD("aad;sflkj;lsdf");
  203.     p = new LAPD("bb");
  204.     delete p;
  205.     delete m;
  206.     delete n;
  207.     delete o;
  208. }
  209.